import { isProxy, toRaw } from 'vue'
import { defineStore } from 'pinia'
import arrayToTree from 'array-to-tree'

import { localCache } from '@/utils/cache'
import {
  reqLogin,
  reqLogout,
  getUserById,
  getRoleById,
  getMenusByRoleIds,
  updateUserById
} from '@/api'
import emitter from '@/emitter'
import { router_change, menu_loading } from '@/emitter'
import type { IUser, ILoginDto } from '@/api/types'
import useMainStore from '../main/main'
import { mapUserMenuListToPermissions } from '@/utils/mapMenus'

type IUpdateUserInfoDto = Partial<
  Omit<IUser, 'createdAt' | 'updatedAt' | '_id' | 'userId'>
>

interface ILoginState {
  token: string
  userInfo?: Partial<IUser>
  userMenus?: any
  permissions: string[]
}
// 定义登录store
const useLoginStore = defineStore('login', {
  // 定义state
  state: (): ILoginState => ({
    token: '',
    userInfo: {},
    userMenus: [],
    permissions: []
  }),
  actions: {
    /**
     * 登录账号
     * @param account 账号信息
     */
    async loginAccount(data: ILoginDto) {
      // 1.处理account
      const account = isProxy(data) ? toRaw(data) : data
      // 2.调用登录接口
      const reslut = await reqLogin(account)
      // 3.处理登录结果
      if (!reslut.success) {
        return Promise.reject(reslut.message)
      }

      // 4.将登录结果存储到pinia中
      const id = reslut.data._id
      const token = reslut.data.access_token
      this.token = token
      // 本地储存最好是原始数据，因为pinia中的数据是响应式的；
      // 将token存储到本地缓存中，方便后续使用；
      // 因为路由拦截器需要使用到token，所以需要先将token存储到本地缓存中；
      localCache.set('TOKEN', token)

      // 5.获取用户信息
      const userInfo = await getUserById(id)
      if (!userInfo.success) {
        return Promise.reject(userInfo.message)
      }
      const user = userInfo.data
      this.userInfo = user
      localCache.set('USERINFO', user)

      //#region 用户菜单
      // 6.获取用户菜单
      // 6.1.获取用户角色
      const roleId = this.userInfo?.roleId
      if (!roleId) return
      const role = await getRoleById(roleId)
      if (!role.success) {
        return Promise.reject(role.message)
      }

      const ids = role.data.menuIds
      if (!ids || ids.length === 0) return

      // 6.2.根据角色id获取菜单信息
      const menus = await getMenusByRoleIds(ids)
      if (!menus.success) {
        return Promise.reject(menus.message)
      }
      const userMenus = menus.data
      const tree = arrayToTree(userMenus, {
        parentProperty: 'parentId',
        customID: '_id',
        childrenProperty: 'children'
      })

      this.userMenus = tree
      // 7.将菜单信息存储到本地缓存中
      localCache.set('MENULIST', tree)

      // 6.3.数组结构转化成树形结构
      // const tree = arrayToTree(userMenus, {
      //   parentProperty: 'parentId',
      //   customID: '_id',
      //   childrenProperty: 'children'
      // })
      // this.userMenus = tree
      // 8.请求所有main state中的菜单信息
      const mainState = useMainStore()
      mainState.fetchEntireDataAction()
      //#endregion

      // 9.获取登录用户的所有按钮权限
      const permissions = mapUserMenuListToPermissions(tree)
      this.permissions = permissions

      // 9.登录成功后添加菜单
      emitter.emit(menu_loading, tree)
      // 10.跳转到首页
      emitter.emit(router_change, '/main')
    },
    /** 加载本地缓存数据行动 */
    async loadLocalCacheAction() {
      const token = localCache.get('TOKEN')
      const userInfo = localCache.get('USERINFO')
      const userMenus = localCache.get('MENULIST')
      if (token && userInfo && userMenus) {
        this.token = token
        this.userInfo = userInfo
        this.userMenus = userMenus

        // 1、请求所有的数据
        const mainStore = useMainStore()
        mainStore.fetchEntireDataAction()

        // 2、获取登录用户的所有按钮权限
        const permissions = mapUserMenuListToPermissions(userMenus)
        this.permissions = permissions

        // 3、添加菜单
        emitter.emit(menu_loading, userMenus)
      }
    },

    async logout() {
      const id = this.userInfo?._id ?? ''
      // 2.服务器发送注销请求，需要token请求
      id && (await reqLogout(id))
      // 4.跳转到登录页
      emitter.emit(router_change, '/login')
      // 3.清除本地缓存sessionStorage
      localCache.remove('USERINFO')
      localCache.remove('MENULIST')
      localCache.remove('TOKEN')
      // 4.pinia重置初始化
      this.$reset()
    },

    storeLoginInfo(accessInfo: ILoginDto) {
      localCache.set('CACHE_NAME', accessInfo.username)
      localCache.set('CACHE_PASSWORD', accessInfo.password)
    },

    clearLoginInfo() {
      localCache.remove('CACHE_NAME')
      localCache.remove('CACHE_PASSWORD')
    },

    async updateUserInfoAction(dto: IUpdateUserInfoDto) {
      const id = this.userInfo?._id ?? ''
      if (!id) return
      await updateUserById(id, dto)
      this.loadLocalCacheAction()
    }
  },
  getters: {
    avatar: (state) => {
      let avatarUrl =
        'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png'
      if (state.userInfo?.avatar) {
        avatarUrl = `http://localhost:3000/static/${state.userInfo.avatar}`
      }
      return avatarUrl
    }
  }
})

export default useLoginStore
